using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

// 定义Windows原生API常量和接口
internal static class FileDialogNative
{
    // 文件对话框选项
    [Flags]
    public enum FOS : uint
    {
        FOS_OVERWRITEPROMPT = 0x2,
        FOS_STRICTFILETYPES = 0x4,
        FOS_NOCHANGEDIR = 0x8,
        FOS_PICKFOLDERS = 0x20,
        FOS_FORCEFILESYSTEM = 0x40,
        FOS_ALLNONSTORAGEITEMS = 0x80,
        FOS_NOVALIDATE = 0x100,
        FOS_ALLOWMULTISELECT = 0x200,
        FOS_PATHMUSTEXIST = 0x800,
        FOS_FILEMUSTEXIST = 0x1000,
        FOS_CREATEPROMPT = 0x2000,
        FOS_SHAREAWARE = 0x4000,
        FOS_NOREADONLYRETURN = 0x8000,
        FOS_NOTESTFILECREATE = 0x10000,
        FOS_HIDEMRUPLACES = 0x20000,
        FOS_HIDEPINNEDPLACES = 0x40000,
        FOS_NODEREFERENCELINKS = 0x100000,
        FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
        FOS_DONTADDTORECENT = 0x2000000,
        FOS_FORCESHOWHIDDEN = 0x10000000,
    }

    // 定义IFileDialog接口
    [ComImport]
    [Guid("42f85136-db7e-439c-85f1-e4075d135fc8")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IFileDialog
    {
        [PreserveSig]
        int Show(IntPtr parent);
        
        void SetFileTypes(uint cFileTypes, IntPtr rgFilterSpec);
        
        void SetFileTypeIndex(uint iFileType);
        
        uint GetFileTypeIndex(out uint piFileType);
        
        void Advise(IntPtr pfde, out uint pdwCookie);
        
        void Unadvise(uint dwCookie);
        
        void SetOptions(FOS fos);
        
        FOS GetOptions(out FOS pfos);
        
        void SetDefaultFolder(IntPtr psi);
        
        void SetFolder(IntPtr psi);
        
        void GetFolder(out IntPtr ppsi);
        
        void GetCurrentSelection(out IntPtr ppsi);
        
        void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        
        void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
        
        void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
        
        void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
        
        void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
        
        void GetResult(out IntPtr ppsi);
        
        void AddPlace(IntPtr psi, uint fdap);
        
        void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
        
        void Close(int hr);
        
        void SetClientGuid(ref Guid guid);
        
        void ClearClientData();
        
        void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);
    }

    // 用于获取路径的接口
    [ComImport]
    [Guid("b63ea76d-1f85-456f-a19c-48159efa858b")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IShellItem
    {
        void BindToHandler(IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv);
        
        void GetParent(out IShellItem ppsi);
        
        void GetDisplayName(uint sigdnName, out IntPtr ppszName);
        
        void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
        
        void Compare(IShellItem psi, uint hint, out int piOrder);
    }

    // 创建文件对话框的工厂类
    [ComImport]
    [Guid("dc1c5a9c-e88a-4dde-a5a1-60f82a20aef7")]
    public class FileOpenDialogRCW
    {
    }

    // 用于获取路径的常量
    public const uint SIGDN_FILESYSPATH = 0x80058000;
}

// 封装原生文件对话框的使用
public class NativeFileDialog
{
    public string Title { get; set; }
    public bool AllowMultiSelect { get; set; }
    public bool AllowFolders { get; set; }

    public string[] ShowDialog(IWin32Window owner = null)
    {
        try
        {
            // 创建文件对话框实例
            FileDialogNative.IFileDialog dialog = new FileDialogNative.FileOpenDialogRCW() as FileDialogNative.IFileDialog;
            
            if (dialog == null)
                return null;

            // 设置对话框选项
            FileDialogNative.FOS options = FileDialogNative.FOS.FOS_FORCEFILESYSTEM;
            
            if (AllowMultiSelect)
                options |= FileDialogNative.FOS.FOS_ALLOWMULTISELECT;
                
            if (AllowFolders)
                options |= FileDialogNative.FOS.FOS_PICKFOLDERS;
                
            dialog.SetOptions(options);

            // 设置标题
            if (!string.IsNullOrEmpty(Title))
                dialog.SetTitle(Title);

            // 显示对话框
            IntPtr parentHandle = owner?.Handle ?? IntPtr.Zero;
            int result = dialog.Show(parentHandle);
            
            if (result != 0) // 0 表示用户点击了确定按钮
                return null;

            // 获取选择结果
            dialog.GetResult(out IntPtr shellItemPtr);
            
            var shellItem = Marshal.GetObjectForIUnknown(shellItemPtr) as FileDialogNative.IShellItem;
            if (shellItem == null)
                return null;

            // 获取选中的路径
            shellItem.GetDisplayName(FileDialogNative.SIGDN_FILESYSPATH, out IntPtr pathPtr);
            string path = Marshal.PtrToStringAuto(pathPtr);
            
            Marshal.FreeCoTaskMem(pathPtr);
            Marshal.ReleaseComObject(shellItem);
            
            return !string.IsNullOrEmpty(path) ? new[] { path } : null;
        }
        catch (Exception ex)
        {
            MessageBox.Show($"对话框错误: {ex.Message}", "错误");
            return null;
        }
    }
}

// 使用示例
public class NativeDialogDemo
{
    public void ShowFileAndFolderDialog()
    {
        var dialog = new NativeFileDialog
        {
            Title = "选择文件或目录",
            AllowMultiSelect = true,
           // AllowFolders = true // 允许选择目录
        };

        var result = dialog.ShowDialog();
        
        if (result != null && result.Length > 0)
        {
            MessageBox.Show($"选中: {string.Join("\n", result)}", "选择结果");
        }
    }
}
